#include "stm32f10x.h"
#include "OLED_Font.h"
#include "string.h"

#define I2C_GPIO GPIOB
#define RCC_I2C_GPIO  RCC_APB2Periph_GPIOB
#define SCL_Pin GPIO_Pin_8
#define SDA_Pin GPIO_Pin_9

void NOLED_SCL_SET(uint8_t Bit)
{
    GPIO_WriteBit(I2C_GPIO, SCL_Pin, Bit);
}

void NOLED_SDA_SET(uint8_t Bit)
{
    GPIO_WriteBit(I2C_GPIO, SDA_Pin, Bit);
}

uint8_t NOLED_SDA_GET()
{
    return GPIO_ReadInputDataBit(I2C_GPIO, SDA_Pin);
}

void NOLED_I2C_Wait_Ack()
{

    NOLED_SCL_SET(1);
    uint8_t read = NOLED_SDA_GET();
    NOLED_SCL_SET(0);
}

void NOLED_Send_Byte(uint8_t Byte)
{
    // I2C protocol write data, scl set low, write bit to sda, scl set high
    // send 1 byte,repeat eight times,first send high bit
    for (int i = 0; i < 8; i++)
    {
        NOLED_SDA_SET(Byte & (0x80 >> i));
        NOLED_SCL_SET(1);
        NOLED_SCL_SET(0);

    }
    NOLED_I2C_Wait_Ack();

}


/** 
 * @param Mode 0-send command 1- send data 
 */
void NOLED_Send_Data_Frame( uint8_t Mode, char Char)
{
    // build data frame
    // slave address
    NOLED_Send_Byte(0x78);
    // control byte 
    // 0000 0000 - send command 
    // 0100 0000 - send data
    NOLED_Send_Byte(0x00 | (Mode << 6)); // 00000001
    // data byte
    NOLED_Send_Byte(Char);

}
/** 
 * init I2C by init SCL pin,SDA pin
 */
void NOLED_I2C_Init() 
{
    // init APB Clock
    RCC_APB2PeriphClockCmd(RCC_I2C_GPIO, ENABLE);
    // init GPIO
    GPIO_InitTypeDef GPIO_Init_Param;
    // use open drain mode
    GPIO_Init_Param.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_Init_Param.GPIO_Pin = SCL_Pin ;
    GPIO_Init_Param.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(I2C_GPIO, &GPIO_Init_Param);
    GPIO_Init_Param.GPIO_Pin =  SDA_Pin;

    GPIO_Init(I2C_GPIO, &GPIO_Init_Param);
    // set scl sda high
    NOLED_SCL_SET(1);
    NOLED_SDA_SET(1);
}



void NOLED_I2C_Start()
{
    // promise scl high, sda from high to low,first set scl high
    NOLED_SDA_SET(1);
    NOLED_SCL_SET(1);
    NOLED_SDA_SET(0);
    NOLED_SCL_SET(0);

}
void NOLED_I2C_End()
{
    // promise scl high, sda from low to high, first set sda low
    NOLED_SDA_SET(0);
    NOLED_SCL_SET(1);
    NOLED_SDA_SET(1);

}
void NOLED_Send_Command(uint8_t Char)
{
    NOLED_I2C_Start();
    NOLED_Send_Data_Frame(0 , Char);
    NOLED_I2C_End();

}

void NOLED_Send_Data(char Char)
{
    NOLED_I2C_Start();
    // todo 
    NOLED_Send_Data_Frame(1 , Char);
    NOLED_I2C_End();
}
void NOLED_Set_Cursor(uint8_t page, uint8_t startColumn)
{
    // set start page, one page = 8 bit
    NOLED_Send_Command(0xB0 | (page));
    // set start column high 4 bit
    NOLED_Send_Command(0x10 | ((startColumn * 8) >> 4) & 0x0F);
    // set start column low 4 bit
    NOLED_Send_Command(0x00 | ((startColumn * 8) & 0x0F));
    // 1000 & 0000 1111

}

/** 
 * font: 1 column use 8 bit , 1 row use 16 bit ,so 1 row = 2 page
 */
void NOLED_ShowChar(uint8_t row, uint8_t startColumn, char Char)
{
    NOLED_Set_Cursor(2 * row, startColumn);
    // send 8 times
    // switch Char to byte with OLED Font code
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        NOLED_Send_Data(OLED_F8x16[Char - ' '][i]);
    }

    NOLED_Set_Cursor(2 * row + 1, startColumn);
    for (;i < 16; i++)
    {
        NOLED_Send_Data(OLED_F8x16[Char - ' '][i]);
    }

}
void NOLED_Clear(void)
{
    for(uint8_t row = 0; row < 8; row++)
    {
        for(uint8_t column = 0; column < 16; column++)
        {
            NOLED_ShowChar(row, column, ' ');
        }
    }
}

void NOLED_Init(void)
{
    // init I2C
    NOLED_I2C_Init();


    // init OLED config
    NOLED_Send_Command(0xAE);	//关闭显示
	
	NOLED_Send_Command(0xD5);	//设置显示时钟分频比/振荡器频率
	NOLED_Send_Command(0x80);
	
	NOLED_Send_Command(0xA8);	//设置多路复用率
    NOLED_Send_Command(0x3F);
	
	NOLED_Send_Command(0xD3);	//设置显示偏移
	NOLED_Send_Command(0x00);
	
	NOLED_Send_Command(0x40);	//设置显示开始行
	
	NOLED_Send_Command(0xA1);	//设置左右方向，0xA1正常 0xA0左右反置
	
	NOLED_Send_Command(0xC8);	//设置上下方向，0xC8正常 0xC0上下反置

	NOLED_Send_Command(0xDA);	//设置COM引脚硬件配置
	NOLED_Send_Command(0x12);
	
	NOLED_Send_Command(0x81);	//设置对比度控制
	NOLED_Send_Command(0xCF);

	NOLED_Send_Command(0xD9);	//设置预充电周期
	NOLED_Send_Command(0xF1);

	NOLED_Send_Command(0xDB);	//设置VCOMH取消选择级别
	NOLED_Send_Command(0x30);

	NOLED_Send_Command(0xA4);	//设置整个显示打开/关闭

	NOLED_Send_Command(0xA6);	//设置正常/倒转显示

	NOLED_Send_Command(0x8D);	//设置充电泵
	NOLED_Send_Command(0x14);

	NOLED_Send_Command(0xAF);	//开启显示
		
	NOLED_Clear();				//OLED清屏

}

void NOLED_ShowString(char *String)
{
    for (uint8_t i = 0; i < strlen(String); i++)
    {
        NOLED_ShowChar(0, i, String[i]);
    }

}
void NOLED_ShowLineString(uint8_t row, uint8_t column, char *String)
{
    for (uint8_t i = 0; i < strlen(String); i++)
    {
        NOLED_ShowChar(row, column + i, String[i]);
    }

}
